include "inttypes.h";

struct MyStruct {
    public var a: Int;
    public var b: Float;
}

trait Greeter {
    public function greet(): Void;
    public function original(): Ptr[Void] {
        return &this;
    }
}

implement Greeter for Int {
    public function greet() {
        printf("Hello from Int %i\n", this);
    }
}

implement Greeter for Int64 {
    public function greet() {
        printf(```"Hellooo from Int64 %" PRId64 "\n"```: CString, this);
    }
}

implement Greeter for Float32 {
    public function greet() {
        printf("Howdy from Float %.2f\n", this);
    }
}

implement Greeter for MyStruct {
    public function greet() {
        printf("Hey from MyStruct\n");
        greet(this.a);
        greet(this.b);
    }
}

implement Greeter for Bool {
    public function greet() {
        if this {
            printf("yep\n");
        } else {
            printf("nope\n");
        }
    }
}

implement Greeter for (Int, Int) {
    public function greet() {
        printf("hello from two ints: (%i, %i)\n", this[0], this[1]);
    }
}

function greet(x: Box[Greeter]) {
    x.greet();
}

function main() {
    var a: Int = 1;
    var x: Box[Greeter] = a;
    greet(x);

    var a1 = (x as Ptr[Void]) as Ptr[Int];
    printf("%i\n", *a1);

    var b = 7_i;
    greet(b);
    greet(5_f32);
    greet(10000000000000_i64);

    greet(struct MyStruct {a: 100, b: 3.14});

    greet(true);
    greet(false);

    greet((3_i, 5_i));

    var original = x.original() as Ptr[Int];
    printf("%i\n", *original);
}
